

lib s = <string.ssz>;
lib consts = <consts.ssz>;
lib se = <alpha/sdlevent.ssz>;
lib sdl = <alpha/sdlplugin.ssz>;
lib mes = <alpha/mesdialog.ssz>;
lib m = <math.ssz>;
lib sff = "sff.ssz";
lib cmd = "command.ssz";
lib fnt = "font.ssz";
lib snd = "sound.ssz";
lib lua = <alpha/lua.ssz>;
lib com = "common.ssz";


public double numArg(&.lua.State L=, int re=, int argc=, int nresults)
{
  double num = 0.0;
  argc++;
  if(!L.isNumber(argc)){
    L.pushString(''argc + "番目の引数が数ではありません。");
    re = -1;
    ret num;
  }
  num = L.toNumber(argc);
  re = nresults;
  ret num;
}

public bool blArg(&.lua.State L=, int re=, int argc=, int nresults)
{
  bool b = false;
  argc++;
  if(!L.isBoolean(argc)){
    L.pushString(''argc + "番目の引数が論理値ではありません。");
    re = -1;
    ret b;
  }
  b = L.toBoolean(argc);
  re = nresults;
  ret b;
}

public ^char strArg(&.lua.State L=, int re=, int argc=, int nresults)
{
  ^char str;
  argc++;
  if(!L.isString(argc)){
    L.pushString(''argc + "番目の引数が文字列ではありません。");
    re = -1;
    ret str;
  }
  str = L.toString(argc);
  re = nresults;
  ret str;
}

public ..refArg<_t>(&.lua.State L=, int re=, int argc=, int nresults) ^_t
{
  ^_t obj;
  argc++;
  ref r = L.toRef(argc);
  r.cast(obj=);
  if(#obj == 0){
    L.pushString(''argc + "番目の引数が不正です。");
    re = -1;
    ret obj;
  }
  re = nresults;
  ret obj;
}

public &Sff
{
  ^&.sff.Sff sff;
  public ^&.sff.Sff getSff()
  {
    ret `sff;
  }
  public bool load(^/char file)
  {
    `sff.new(1);
    ret #`sff~loadFile(file, false) == 0;
  }
}
void sffNew(&.lua.State L=, int re=)
{
  int argc = 0, nret = 1;
  ^/char file = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  ^&.Sff sff.new(1);
  if(!sff~load(file)){
    L.pushString(file + "のロードに失敗しました。");
    re = -1;
    ret;
  }
  L.pushRef(sff);
}


public &Snd
{
  ^&.snd.Snd snd;
  public ^&.snd.Snd getSnd()
  {
    ret `snd;
  }
  public bool load(^/char file)
  {
    `snd.new(1);
    ret #`snd~loadFile(file) == 0;
  }
  public bool play(int g, int n)
  {
    if(#`snd == 0) ret false;
    ^&.snd.Sound c = .snd.getChannel(-1);
    if(#c == 0) ret false;
    c~sound = `snd~getSound(g, n);
    ret #c~sound > 0;
  }
}
void sndNew(&.lua.State L=, int re=)
{
  int argc = 0, nret = 1;
  ^/char file = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  ^&.Snd snd.new(1);
  if(!snd~load(file)){
    L.pushString(file + "のロードに失敗しました。");
    re = -1;
    ret;
  }
  L.pushRef(snd);
}
void sndPlay(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  ^&.Snd snd = .refArg!&.Snd?(L=, re=, argc=, nret); if(re < 0) ret;
  int g = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  int n = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  snd~play(g, n);
}


public &Font
{
  ^&.fnt.Font fnt;
  public ^&.fnt.Font getFont()
  {
    ret `fnt;
  }
  public bool load(^/char file)
  {
    `fnt.new(1);
    ret #`fnt~loadFile(file) == 0;
  }
}
void fontNew(&.lua.State L=, int re=)
{
  int argc = 0, nret = 1;
  ^/char file = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  ^&.Font font.new(1);
  if(!font~load(file)){
    L.pushString(file + "のロードに失敗しました。");
    re = -1;
    ret;
  }
  L.pushRef(font);
}


public &Command
{
  ^&.cmd.CommandList cmd;
  new()
  {
    `cmd.new(1);
    `cmd~buffer.new(1);
  }
  public void input(int pn)
  {
    if(`cmd~input(pn-1, 1)) `cmd~step(1, false, false, 0);
  }
  public bool getState(^/char name)
  {
    ^&.cmd.Command cl = `cmd~get(name);
    loop{index i = 0; while; do:
      if(cl[i].curbuftime > 0) ret true;
      i++;
    while i < #cl:}
    ret false;
  }
  public void addCommand(^/char name, ^/char com, int time)
  {
    &.cmd.Command c;
    c.name = name;
    .cmd.resetReadKeymap();
    c.readCmd(com);
    c.time = time;
    `cmd~add(c=);
  }
  public void bufReset()
  {
    `cmd~bufReset();
  }
}
void commandNew(&.lua.State L=, int re=)
{
  re = 1;
  ^&.Command command.new(1);
  L.pushRef(command);
}
void commandAdd(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  ^&.Command command = .refArg!&.Command?(L=, re=, argc=, nret);
  if(re < 0) ret;
  ^/char name = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  ^/char com = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  int time = 1;
  if(L.getTop() > argc){
    time = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  }
  command~addCommand(name, com, time);
}
void commandGetState(&.lua.State L=, int re=)
{
  int argc = 0, nret = 1;
  ^&.Command command = .refArg!&.Command?(L=, re=, argc=, nret);
  if(re < 0) ret;
  ^/char name = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  L.pushBoolean(command~getState(name));
}
void commandInput(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  ^&.Command command = .refArg!&.Command?(L=, re=, argc=, nret);
  if(re < 0) ret;
  int pn = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  command~input(pn);
}
void commandBufReset(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  ^&.Command command = .refArg!&.Command?(L=, re=, argc=, nret);
  if(re < 0) ret;
  command~bufReset();
}


void inputThread(^/char title, ^^char str, ^bool done)
{
  .mes.InputStr(:title, str<>=:);
  done<> = true;
}
public &InputDialog
{
  thread!.inputThread? inth;
  ^^char str;
  ^bool done;
  new()
  {
    `str.new(1);
    `done.new(1);
    `done<> = true;
  }
  public bool popup(^/char title)
  {
    if(!`done<>) ret false;
    .sdl.fullScreen(.se.full = false);
    `done<> = false;
    `inth..(title, `str, `done);
    ret true;
  }
  public bool isDone()
  {
    ret `done<>;
  }
  public ^char getStr()
  {
    if(!`done<>) ret .consts.null!char?();
    ret `str<>;
  }
}
void inputDialogNew(&.lua.State L=, int re=)
{
  re = 1;
  ^&.InputDialog inputDialog.new(1);
  L.pushRef(inputDialog);
}
void inputDialogPopup(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  ^&.InputDialog inputDialog = .refArg!&.InputDialog?(L=, re=, argc=, nret);
  if(re < 0) ret;
  ^/char title = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  inputDialog~popup(title);
}
void inputDialogIsDone(&.lua.State L=, int re=)
{
  int argc = 0, nret = 1;
  ^&.InputDialog inputDialog = .refArg!&.InputDialog?(L=, re=, argc=, nret);
  if(re < 0) ret;
  L.pushBoolean(inputDialog~isDone());
}
void inputDialogGetStr(&.lua.State L=, int re=)
{
  int argc = 0, nret = 1;
  ^&.InputDialog inputDialog = .refArg!&.InputDialog?(L=, re=, argc=, nret);
  if(re < 0) ret;
  L.pushString(inputDialog~getStr());
}


void playBGM(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  ^/char file = .strArg(L=, re=, argc=, nret); if(re < 0) ret;
  .snd.bgm~play(file);
}

void esc(&.lua.State L=, int re=)
{
  re = 1;
  L.pushBoolean(.se.esc);
}

void sszRandom(&.lua.State L=, int re=)
{
  re = 1;
  L.pushNumber((double).m.random());
}

void setAutoguard(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  int pn = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  if(!.m.inRange!int?(1, #.com.autoguard, pn)){
    L.pushString("プレイヤー番号が不正です。");
    re = -1;
    ret;
  }
  bool ag = .blArg(L=, re=, argc=, nret); if(re < 0) ret;
  .com.autoguard[pn-1] = ag;
}

void setPowerShare(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  int pn = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  if(!.m.inRange!int?(1, #.com.powerShare, pn)){
    L.pushString("チーム番号が不正です。");
    re = -1;
    ret;
  }
  bool ps = .blArg(L=, re=, argc=, nret); if(re < 0) ret;
  .com.powerShare[pn-1] = ps;
}

void setRoundTime(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  int rt = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  .com.roundTime = rt;
}

void getRoundTime(&.lua.State L=, int re=)
{
  re = 1;
  L.pushNumber((double).com.roundTime);
}

void setHomeTeam(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  int tn = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  if(!.m.inRange!int?(1, 2, tn)){
    L.pushString("チーム番号が不正です。");
    re = -1;
    ret;
  }
  .com.home = tn - 1;
}

void setMatchNo(&.lua.State L=, int re=)
{
  int argc = 0, nret = 0;
  int mn = (int).numArg(L=, re=, argc=, nret); if(re < 0) ret;
  .com.match = mn;
}

public void init(&.lua.State L=)
{
  L.register("sffNew", .sffNew);
  L.register("sndNew", .sndNew);
  L.register("sndPlay", .sndPlay);
  L.register("fontNew", .fontNew);
  L.register("commandNew", .commandNew);
  L.register("commandAdd", .commandAdd);
  L.register("commandGetState", .commandGetState);
  L.register("commandInput", .commandInput);
  L.register("commandBufReset", .commandBufReset);
  L.register("inputDialogNew", .inputDialogNew);
  L.register("inputDialogPopup", .inputDialogPopup);
  L.register("inputDialogIsDone", .inputDialogIsDone);
  L.register("inputDialogGetStr", .inputDialogGetStr);
  L.register("playBGM", .playBGM);
  L.register("esc", .esc);
  L.register("sszRandom", .sszRandom);
  L.register("setAutoguard", .setAutoguard);
  L.register("setPowerShare", .setPowerShare);
  L.register("setRoundTime", .setRoundTime);
  L.register("getRoundTime", .getRoundTime);
  L.register("setHomeTeam", .setHomeTeam);
  L.register("setMatchNo", .setMatchNo);
}


